﻿using System.ComponentModel.DataAnnotations;
using Blazor.Util.Const;

namespace Blazor.Validators;

public class ComparisonAttribute: CompareAttribute
{
		private readonly ComparisonOperator _comparisonOperator;

		public ComparisonAttribute(string otherPropertyName, ComparisonOperator comparisonOperator): base(otherPropertyName)
		{
			_comparisonOperator = comparisonOperator;
		}

		protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
		{
			var otherPropertyInfo = validationContext.ObjectType.GetProperty(OtherProperty);
			if (otherPropertyInfo == null)
			{
				return new ValidationResult(string.Format(ValidatorLocalization.CannotFindTargetProperty, OtherProperty));
			}
			var otherValue = otherPropertyInfo.GetValue(validationContext.ObjectInstance);
			if (!IsValidValue(value) || !IsValidValue(otherValue))
			{
				return ValidationResult.Success;
			}

			var comparisonResult = System.Collections.Comparer.Default.Compare(value, otherValue);
			var message = ValidatorLocalization.ComparisonNotMeetTip;
			return _comparisonOperator switch
			{
				ComparisonOperator.Equal => comparisonResult == 0 ? ValidationResult.Success : new ValidationResult(message),
				ComparisonOperator.NotEqual => comparisonResult != 0 ? ValidationResult.Success : new ValidationResult(message),
				ComparisonOperator.GreaterThan => comparisonResult > 0 ? ValidationResult.Success : new ValidationResult(message),
				ComparisonOperator.GreaterThanOrEqual => comparisonResult >= 0 ? ValidationResult.Success : new ValidationResult(message),
				ComparisonOperator.LessThan => comparisonResult < 0 ? ValidationResult.Success : new ValidationResult(message),
				ComparisonOperator.LessThanOrEqual => comparisonResult <= 0 ? ValidationResult.Success : new ValidationResult(message),
				_ => new ValidationResult(string.Format(ValidatorLocalization.InvalidOperator, _comparisonOperator)),
			};
		}


		private static bool IsValidValue(object? value)
		{
			return value is not null && value != DBNull.Value;
		}

		public override string FormatErrorMessage(string name)
		{
			var message = ValidatorLocalization.ComparisonNotMeetTip;
			return string.Format(message, name, GetOperatorLocalization(), OtherProperty);
		}

		private string GetOperatorLocalization()
		{
			return _comparisonOperator switch
			{
				ComparisonOperator.Equal => ValidatorLocalization.Equal,
				ComparisonOperator.NotEqual => ValidatorLocalization.NotEqual,
				ComparisonOperator.GreaterThan => ValidatorLocalization.GreaterThan,
				ComparisonOperator.GreaterThanOrEqual => ValidatorLocalization.GreaterThanOrEqual,
				ComparisonOperator.LessThan => ValidatorLocalization.LessThan,
				ComparisonOperator.LessThanOrEqual => ValidatorLocalization.LessThanOrEqual,
				_ => throw new ArgumentOutOfRangeException(),
			};
		}
}